# coding=utf-8
import binascii
import struct
from time import sleep

from bluepy import btle
from bluepy.btle import DefaultDelegate, UUID, Peripheral, BTLEDisconnectError, BTLEGattError, Scanner


class HandlerDelegate(DefaultDelegate):
    # Constructor (run once on startup)
    def __init__(self):
        DefaultDelegate.__init__(self)

    # func is caled on notifications
    def handleNotification(self, cHandle, data):
        b = bytearray()
        b.extend(data)
        print binascii.hexlify(b)
        # print ("Notification from Handle: 0x" + format(cHandle, '02X') + " Value: " + format(ord(data[0])))


mac = "00:a0:50:0a:1b:20"
# Initialisation  -------
service_uuid = UUID("49535343-FE7D-4AE5-8FA9-9FAFD205E455")
char_uuid = UUID("49535343-1E4D-4BD9-BA61-23C647249616")


def main_loop(p):
    service = p.getServiceByUUID(service_uuid)
    character = service.getCharacteristics(char_uuid)[0]
    hnd = character.getHandle()
    # Search and get Get The Bracelet-Characteristics "property" (UUID-0x2902 CCC-Client Characteristic Configuration))
    #  wich is located in a handle in the range defined by the boundries of the BraceletService
    for descriptor in p.getDescriptors(hnd, 0x00F):  # The handle range should be read from the services
        if descriptor.uuid == 0x2902:  # but is not done due to a Bluez/BluePy bug :(
            print ("Bracelet Client Characteristic Configuration found at handle 0x"
                   + format(descriptor.handle, "02X"))
            h_bracelet_ccc = descriptor.handle

    # Turn notifications on by setting bit0 in the CCC more info on:
    # https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
    p.writeCharacteristic(hnd-1, struct.pack('<bb', 0x01, 0x00))
    print "Notification is turned on for Bracelet"
    # Main loop --------
    while True:
        if p.waitForNotifications(3.0):
            continue

        print "Waiting... Waited more than one sec for notification"


def reconnect(addr, type):
    while True:
        try:
            p = Peripheral(addr, type)
            p.setDelegate(HandlerDelegate())
            print u'bracelet {} connected '.format(addr)
            main_loop(p)
        except BTLEDisconnectError:
            print u'disconnect from bracelet {}'.format(addr)
        except BTLEGattError:
            print u'connect to bracelet {} fail'.format(addr)
        else:
            print u'connection from bracelet {}is down'.format(addr)
        sleep(2.0)


def scan(d):
    scanner = Scanner()
    oximeter = None
    while oximeter is None:
        devices = scanner.scan(10.0)
        for dev in devices:
            # print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
            for (adtype, desc, value) in dev.getScanData():
                if desc == 'Manufacturer':
                    d['Manufacturer'] = value
                if desc == "Complete Local Name":
                    d['CompleteLocalName'] = value
                print ("{} {}".format(desc, value))
            print '-------------'
            if d['Manufacturer'] is not None and d['Manufacturer'].startswith('31013b04'):
                print 'find you! %s %s ' % (dev.addr, dev.addrType)
                oximeter = dev
                break
            print 'oximeter not in range, continue'
    return oximeter


if __name__ == "__main__":
    d = {}
    btle.Debugging = True
    bracelet = scan(d)
    # p = Peripheral(bracelet.addr, bracelet.addrType)
    reconnect(bracelet.addr, bracelet.addrType)
